const fs = require("fs")
const http = require("http")
const path = require("path")

const VIEWPATH = './view/'

/**
 * 绑定一处url 与 文件 进行实时查询
 * 
 * @param {String} giveUrl 希望分发的url，绑定开头需要的url
 * @param {String} giveFilePos 给予希望公开的文件夹， 系统将以此为根目录，请在传入时传入绝对路径，防止寻找错误
 * @param {*} onPort 监听的端口
 */
function mark (giveFilePos = path.join(__dirname, "test"), onPort = 3000, giveUrl = '/'){
    // 先实现一个固定访问， 再考虑是否可以作为中间件实现
    this.server = http.createServer(async (req, res) =>{
        let url = req.url
        url = decodeURI(url)
        if (url.indexOf(giveUrl) === 0){
            // 如果存在向上访问这类通配则不得返回
            if (url.indexOf("..") !== -1){
                res.end('can\'t have ".."');
            }

            // 开始监听
            url = url.slice(giveUrl.length)
            //处理公开文件访问 [node_modules, view]
            if (url.indexOf('/node_modules') == 0 || url.indexOf('node_modules') == 0){
                // 公开 node_modules
                fs.readFile(path.join(__dirname, url), (err, data)=>{

                    if (err){
                        res.end('404');
                    }else{
                        res.end(data);
                    }
                });
                return;
            }
            if (url.indexOf('/view') == 0 || url.indexOf('view') == 0){
                // 公开view 文件夹
                if (url.indexOf('/') === 0){
                    url = url.slice(5)
                }else{
                    url = url.slice(4)
                }
                fs.readFile(path.join(__dirname,VIEWPATH ,url), (err, data)=>{

                    if (err){
                        res.end(404)
                    }else{
                        res.end(data)
                    }
                })
                return
            }

            if (url.endsWith('/')){
                // 此处处理回传数据
                url = url.slice(0,url.length - 1)
                url = decodeURI(url)
                let filePath = path.join(giveFilePos, url)
                if  (checkVideo(url)){
                    // 视频

                    res.setHeader("Content-Type", "video/mpeg4")
                    res.setHeader("char-set", 'utf-8')

                    

                    // 尝试读取大文件 暂时封印

                    let fileSize = fs.statSync(filePath)
                    if (fileSize.size > 2){
                        // res.writeHead(206)
                        // let parts = range.replace(/bytes=/, "").split("-")
                        // let start = parseInt(parts[0], 10)
                        // let end = parts[1] ? parseInt(parts[1], 10) : start + 999999

                        // end = end > fileSize-1 ? fileSize-1: end

                        // let chunkSize = (end - start) +1
                        // let stream = fs.createReadStream(filePath, {start, end})

                        try {
                            let readstream = fs.ReadStream(filePath)
                        
                            res.writeHead(200, {
                                'Accept-Ranges' : 'bytes',
                                'Server' : 'Microsoft-IIS/7.5',
                                'X-Powered-By' : 'ASP.NET'
                            })

                            readstream.on('close', ()=>{
                                res.end()
                                console.log("传输结束")
                            })

                            readstream.pipe(res)

                        } catch (error) {
                            console.log("err when send big video file")
                            console.log(error)
                        }
                    }else{
                        console.log(fileSize)

                        fs.readFile(filePath,(err, data)=>{

                            if (err){
                                console.log(err)
                                res.end('404')
                            }
                            res.end(data)
                        })
                    }

                    

                    return
                }else if (checkImg(url)){
                    // 图片列表

                    res.setHeader("Content-Type", "image")
                    res.setHeader("char-set", 'utf-8')

                    fs.readFile(filePath, (err, data) =>{
                        
                        if (err){
                            res.end('404')
                        }else{
                            res.end(data)
                        }
                    })
                    return
                }else{
                    // 文件夹项目

                    res.setHeader("Content-Type", "text/text")
                    res.setHeader("char-set", 'utf-8')

                    let f = async function(){
                        return new Promise((resolve, reject)=>{
                            // 如果不和规定则返回null
                            fs.exists(filePath, (e)=>{
                                
                                if (e){
                                    fs.stat(filePath, (err, data)=>{
                    
                                        if (err) {
                                            resolve(null)
                                        }
                                        if (data.isDirectory()){ //是文件夹
                                            
                                            fs.opendir(filePath,async (err, dir)=>{
                    
                                                if (err){
                                                    resolve("404")
                                                }
                                                let rtList = []
                                                do{
                                                    rtList[rtList.length] = await dir.read()
                                                }while (rtList[rtList.length - 1])
                                                dir.close()
                                                resolve(rtList)
                                            })
                                        }
                                    })
                                }else{
                                    resolve(null)
                                }
                            })
                        })
                    }
                    let goodflod = await f()
                    
                    
                    if (goodflod){
                        let fileData = []
                        for (let i=0; i<goodflod.length; i++){
                            if (goodflod[i]){
                                fileData[fileData.length] = {
                                    "name": goodflod[i].name ,
                                    "type": goodflod[i].isFile() ,
                                    "size": goodflod[i].size
                                }
                            }
                        }
                        res.end(JSON.stringify(fileData))
                    }else{
                        res.end('404')
                    }
                    return
                }
            }else{
                //此处处理回传页面
                let filePath = path.join(giveFilePos, url)
                if (url.endsWith('html')){

                    fs.readFile(filePath, (err, data)=>{
                        if (err) res.end("404")
                        else{
                            res.end(data)
                        }
                        return
                    })
                }else if (checkVideo(url)){
                    // 视频页面
                    fs.readFile(path.join(__dirname, VIEWPATH, "html/video.html"), (err, data) =>{

                        if (err){
                            res.end('404')
                        }else{
                            res.end(data)
                        }
                    })
                    return
                }else if (checkImg(url)){
                    // 图片页面
                    fs.readFile(path.join(__dirname, VIEWPATH, "html/imgList.html"), (err, data) =>{

                        if (err){
                            res.end('404')
                        }else{
                            res.end(data)
                        }
                    })
                    return
                }else{
                    // 文件夹页面
                    fs.readFile(path.join(__dirname, VIEWPATH,"html/fileList.html"), (err, data) =>{

                        if (err){
                            res.end("404")
                        }else{
                            res.end(data)
                        }
                        return
                    })
                }
            }
        }else{
            res.end("404")
            return
        }
    })

    // feat：在此实现对端口占用的查找与转换
    this.PORT = onPort;
}

/**
 * 启动服务并监听
 * @param {Boolean} log 是否输出监听
 */
function run(log = false){

    this.server.listen(this.PORT, (err) =>{
        if (! log) return;
        if (err){
            console.log('err when listen');
        }else{
            console.log(`run at port: ${this.PORT}, and ip:`);
            let ips = getIPAdress();
            for (let ip of ips){
                console.log(ip);
            }
        }
    });
}

function stop(log = false){

    this.server.close((err)=>{
        if (! log) return;
    });
}
// 支持的视频类型
const videoList = ['mp4','mkv']

/**
 * 判断文件是否为支持的视频文件
 * @param {string} fileName 判断的文件名
 */
function checkVideo (fileName) {
    for (let i=0; i<videoList.length; i++){
        if ( fileName.endsWith('.' + videoList[i])){
            return true;
        }
    }
    return false;
}

// 支持的图片类型
const imgList = ['png','jpg','bmp','jpeg','webp','psd']

/**
 * 判断文件是否为支持的图片文件
 * @param {string} fileName 判断的文件名
 */
function checkImg (fileName) {
    for (let i=0; i< imgList.length; i++){
        if ( fileName.endsWith('.' + imgList[i])) {
            return true;
        }
    }
    return false;
}

/**
 * 获取所有本机的ip4地址
 * @returns 存放ip4地址的数组
 */
function getIPAdress () {
    const interfaces = require('os').networkInterfaces();
    const ans = [];
    for(let devName in interfaces){
        let iface = interfaces[devName];
        for(let i=0;i<iface.length;i++){
            let alias = iface[i];
            if(alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal){
                ans.push(alias.address);
            }
        }
    }
    return ans;
}

exports.mark = mark;
exports.run = run;
exports.stop = stop;